﻿unit ViewPiece;

//棋子显示类

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls
  ,Math
  ,Direct2D,D2D1
  , Piece;

type

  TAlphaRec = record
    x:Integer;
    y:Integer;
    b:Byte;
    g:Byte;
    r:Byte;
    a:Byte;
  end;
  PAlphaRec = ^TAlphaRec;

  { TViewPiece }

  TViewPiece = class(TImage)
  private
    FAID: AnsiString;
    FCode: AnsiChar;
    FCName: String;
    FDLen: Integer;
    FinI: Byte;
    FinJ: Byte;
    FinL: Integer;
    FinT: Integer;
    FInversion: Boolean;
    FisOnBoard: Boolean;
    FSide: AnsiChar;
    vtmpBitmap: TBitmap;
    FbackImage: TImage;

  protected
  public
    aryAlphas: Array of TAlphaRec;
    aryACount:Integer;
    property AID :AnsiString read FAID Write FAID;
    property Code :AnsiChar read FCode Write FCode;
    property CName :String read FCName Write FCName;
    property DLen :Integer read FDLen Write FDLen;
    property Inversion :Boolean read FInversion Write FInversion;
    property Side :AnsiChar read FSide Write FSide; //B/R
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure PaintImg;
    procedure pAdjustAlpha;
  public
    //on board info
    property inI :Byte read FinI Write FinI; //from left to right 在棋盘中的位置
    property inJ :Byte read FinJ Write FinJ; //from top to bottom 在棋盘中的位置
    property isOnBoard :Boolean read FisOnBoard Write FisOnBoard;
    //on Box info
    property inL :Integer read FinL Write FinL; //在棋盒中的Left
    property inT :Integer read FinT Write FinT; //在棋盒中的Top

    property backImage:TImage read FbackImage write FbackImage;

  end;

  var cBackColor:TColor = $004FBF8F; //BGR
  var cFaceColor:TColor = $00E7F7E7; //BGR

implementation

{ TViewPiece }

constructor TViewPiece.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FCode:='E';
  FDLen:=64;
  FCName:='師';
end;

destructor TViewPiece.Destroy;
begin
  if Assigned(vtmpBitmap) then
    vtmpBitmap.free;
  inherited Destroy;
end;

procedure TViewPiece.pAdjustAlpha;
var nCn,nIx:Integer;
  b_A, b_B, b_G, b_R: byte;
  bbB, bbG, bbR: byte;
  bfB, bfG, bfR: byte;
  bdClr,egClr:TColor;
  aPtB,aPtV,aPtS:TPoint;
begin
  if ((self.backImage<>nil) and self.backImage.Visible)  then
  begin
  //bbB := (cBackColor and $FF0000) shr 16;
  //bbG := (cBackColor and $FF00) shr 8;
  //bbR := (cBackColor and $FF);
  bfB := (cFaceColor and $FF0000) shr 16;
  bfG := (cFaceColor and $FF00) shr 8;
  bfR := (cFaceColor and $FF);
    nCn:=Self.aryACount;
    for nIx := 0 to nCn-1 do
    begin
      aPtV.X :=Self.aryAlphas[nIx].x;
      aPtV.y :=Self.aryAlphas[nIx].y;
      b_A:=Self.aryAlphas[nIx].a;
      aPtS :=Self.ClientToScreen(aPtV);
      aPtB :=backImage.ScreenToClient(aPtS);
      if ((aPtB.X>=0) and (aPtB.X<backImage.Width) and (aPtB.Y>=0) and (aPtB.Y<backImage.Height)) then
      begin
      bdClr:=backImage.Canvas.Pixels[aPtB.X,aPtB.Y];
      bbB := (bdClr and $FF0000) shr 16;
      bbG := (bdClr and $FF00) shr 8;
      bbR := (bdClr and $FF);
      b_B := Round((bbB*(255-b_A) + bfB*b_A)/255);
      b_G := Round((bbG*(255-b_A) + bfG*b_A)/255);
      b_r := Round((bbR*(255-b_A) + bfR*b_A)/255);
      egClr:=RGB(b_r,b_G,b_B);
      Self.Canvas.Pixels[aPtV.X,aPtV.y]:=egClr;
      end;
    end;
  end;
end;

//Draw to vtmpBitmap
procedure TViewPiece.PaintImg;
var
  aBmp: TBitmap;
  Ox, Oy, Rx, Ry , Rxt, Ryt: single;
  aCa,aCs: TColor;
  inEdg,OtEdg,xt,yt,txH,txW:Integer;
  siz1,sizx:Integer;
  sNam:string;
  aClrp,aSwapC:TColor;
  d2dCanvas: TDirect2DCanvas;
  aEllipse: TD2D1Ellipse;
  nIx:Integer;
  b_A, b_B, b_G, b_R: byte;
  bbB, bbG, bbR: byte;
  bfB, bfG, bfR: byte;
  aARec:TAlphaRec;
  f_AB,f_AG,f_AR:Single;
begin
  inEdg:=4;
  otEdg:=1;
  //Self.Picture.Bitmap;
  Self.Width:=Self.DLen;
  Self.Height:=Self.DLen;
  Self.Picture.Bitmap.SetSize(Self.Width,Self.Height);
  Self.Transparent := False;
  Self.Canvas.Brush.Color := cBackColor;//clBlue;//clWhite;
  Self.Canvas.Brush.Style := TBrushStyle.bsSolid;
  Self.Canvas.FillRect(Rect(0, 0, Self.Width, Self.Height));
  Self.Transparent:=False;
  aBmp := TBitmap.Create();
  try
  aBmp.SetSize(Self.DLen,Self.DLen);
  aBmp.PixelFormat:=TPixelFormat.pf24bit;

  aBmp.Canvas.Brush.Color := cBackColor;//clBlue;//clWhite;
  aBmp.Canvas.Brush.Style := TBrushStyle.bsSolid;
  aBmp.Canvas.FillRect(Rect(0, 0, Self.Width, Self.Height));

  //aBmp.Canvas.Pen.Color:=clRed;
  //aBmp.Canvas.Pen.Width:=4;
  //aBmp.Canvas.AntialiasingMode:=amOn;
//  Ox := (Self.Width - 1) / 2;
//  Oy := (Self.Width - 1) / 2;
//  Rx := (Self.Width - 1- otEdg*2) / 2;
//  Ry := (Self.Height - 1- otEdg*2) / 2;
  aCa := cFaceColor; //BGRA(210,230,180,255)

  ///aBmp.Canvas.Pen.Color :=RGB(1, 1, 1); //作为Alpha通道掩模定位色
  ///aBmp.Canvas.Pen.Width :=1;
  ///aBmp.Canvas.Pen.Style :=TPenStyle.psSolid;
  ///aBmp.Canvas.Brush.Color:=aCa;
  ///aBmp.Canvas.Brush.Style:=TBrushStyle.bsSolid;
  ///aBmp.Canvas.Ellipse(otEdg, otEdg, Width-otEdg, Height-otEdg);
  //以上区域是与棋盘相交边界

  //下面用Direct2D绘图
  d2dCanvas := TDirect2DCanvas.Create(aBmp.Canvas, Rect(0, 0, aBmp.Width, aBmp.Height));
  try
  //Rx := Trunc((Self.Width-1 - inEdg*2) / 2 );
  //Ry := Trunc((Self.Height-1 - inEdg*2) / 2 );
  if Self.Side =cSideBlk then
  begin
    aCs:=RGB(20, 20, 25);
  end else
  begin
    aCs:=RGB(255, 1, 1);
  end;


  ///aBmp.Canvas.Brush.Style:=TBrushStyle.bsClear;
  ///aBmp.Canvas.Pen.Width:=(inEdg-otEdg);
  ///aBmp.Canvas.Pen.Color:=aCs;
  ///aBmp.Canvas.Ellipse(inEdg, inEdg, Width-inEdg, Height-inEdg);

  d2dCanvas.BeginDraw;

  ///d2dCanvas.Brush.Color:=RGB(1, 1, 1);//cBackColor;
  ///d2dCanvas.Pen.Color := RGB(1, 1, 1);
  d2dCanvas.Brush.Color:=cFaceColor;//cBackColor;
  d2dCanvas.Pen.Color := cFaceColor;
  d2dCanvas.Pen.Width := 1;
  d2dCanvas.Ellipse(otEdg,otEdg,Width-otEdg, Height-otEdg);

  d2dCanvas.EndDraw;
  //记录抗锯齿Alpha点:
  bbB := (cBackColor and $FF0000) shr 16;
  bbG := (cBackColor and $FF00) shr 8;
  bbR := (cBackColor and $FF);
  bfB := (cFaceColor and $FF0000) shr 16;
  bfG := (cFaceColor and $FF00) shr 8;
  bfR := (cFaceColor and $FF);
  SetLength(Self.aryAlphas,Self.DLen*5);
  nIx:=0;
  for yt := 0 to aBmp.Height-1 do
  begin
    for xt := 0 to aBmp.Width-1 do
    begin
      aClrp:=aBmp.Canvas.Pixels[xt,yt];
      if (aClrp<>cBackColor)and(aClrp<>cFaceColor) then
      begin
        b_B := (aClrp and $FF0000) shr 16;
        b_G := (aClrp and $FF00) shr 8;
        b_R := (aClrp and $FF);
        if (nIx>=Length(aryAlphas)-1) then
        begin
          SetLength(aryAlphas,(nIx+10))
        end;
        aryAlphas[nIx].x:=xt;
        aryAlphas[nIx].y:=yt;
        aryAlphas[nIx].b:=b_B;
        aryAlphas[nIx].g:=b_G;
        aryAlphas[nIx].r:=b_R;
        //方程:
        //bbB*(1-f_AB)+bfB*f_AB = b_B;
        //bbB + (bfB- bbB)*f_AB = b_B;
        if ((bfB- bbB)=0) then
        begin
        f_AB:=0.0; //全透明
        end else
        begin
        f_AB:=(b_B-bbB)/(bfB- bbB);
        end;
        if ((bfG- bbG)=0) then
        begin
        f_AG:=0.0; //全透明
        end else
        begin
        f_AG:=(b_G-bbG)/(bfG- bbG);
        end;
        if ((bfR- bbR)=0) then
        begin
        f_AR:=0.0; //全透明
        end else
        begin
        f_AR:=(b_R-bbR)/(bfR- bbR);
        end;
        b_A:=Round(255*(f_AB+f_AG+f_AR)/3);
        aryAlphas[nIx].a:=b_A;
        Inc(nIx);
      end;
    end;
  end;
  aryACount:=nIx;

  d2dCanvas.BeginDraw;

  d2dCanvas.Brush.Color:=cFaceColor;
  d2dCanvas.Pen.Color := aCs;
  d2dCanvas.Pen.Width := (inEdg-otEdg-1);
  d2dCanvas.Ellipse(inEdg,inEdg,Width-inEdg, Height-inEdg);

  aEllipse.point:=Point(Round(Width/2+0.0),Round(Height/2+0.0)); //中心点
  aEllipse.radiusX:=(Width/2-inEdg);  //X半径
  aEllipse.radiusY:=(Height/2-inEdg); //Y半径
  ///d2dCanvas.FillEllipse(aEllipse);

  d2dCanvas.EndDraw;

  //Ellipse(7,7,Image2.Width-8,Image2.Height-8);
  Self.Picture.Bitmap.Canvas.Draw(0,0,aBmp);
  finally
    d2dCanvas.Free;
  end;
  finally
    aBmp.Free;
  end;
    Self.Picture.Bitmap.TransparentColor:=cBackColor;
    Self.Picture.Bitmap.TransparentMode :=tmFixed;
    Self.Transparent:=True;

  Rx := Trunc((Self.Width -1 - inEdg*2) / 2 );
  Ry := Trunc((Self.Height-1 - inEdg*2) / 2 );

  Self.Canvas.Font.CharSet := GB2312_CHARSET;
  // = 134;//LCLType.FCS_ISO_10646_1 ;// = 4;  // Unicode;
  Self.Canvas.Font.Name := '楷体';
  Self.Canvas.Font.Color := aCs;
  Self.Canvas.Brush.Style := TBrushStyle.bsClear;
  Self.Canvas.Font.Style := [fsBold];
  Self.Canvas.Font.Quality:=fqProof;//fqCleartypeNatural;//fqProof;   fqCleartypeNatural  fqAntialiased  fqCleartype
  sNam:=Self.CName;
  siz1:=12;
  sizx:=siz1;
  txH:=0; txW:=0;
  Rxt:= Trunc(Rx);
  Ryt:= Trunc(Ry);
  //Memo1.Lines.Add('Rxt:'+FloatToStr(Rxt));
  //Memo1.Lines.Add('Ryt:'+FloatToStr(Ryt));
  while (sizx<78) do
  begin
    Self.Canvas.Font.Size := sizx;
    txW:=Self.Canvas.TextWidth(sNam);
    txH:=Self.Canvas.TextHeight(sNam);

    if (txW>=Rxt*2)or(txH>=Ryt*2) then
    begin
      if (sizx>19) then
      sizx:=sizx-2
      else
      sizx:=sizx-1;
      Self.Canvas.Font.Size := sizx;
      txW:=Self.Canvas.TextWidth(sNam);
      txH:=Self.Canvas.TextHeight(sNam);
      //Memo1.Lines.Add('Size:'+IntToStr(sizx)+',txW:'+IntToStr(txW)+',txH:'+IntToStr(txW));
      break;
    end;
    sizx:=sizx +1;
  end;
  xt:=Trunc((Width - txW) / 2);
  yt:=Trunc((Height- txH) / 2);
  //Memo1.Lines.Add('sNam:'+sNam+',xt:'+IntToStr(xt)+',yt:'+IntToStr(yt));
  Self.Canvas.TextOut(xt, yt, sNam);

  if (Inversion) then
  begin
    {
    vtmpBitmap := TBitmap.Create;
    vtmpBitmap.Transparent:=False;
    //vtmpBitmap.TransparentMode:=tmFixed;
    //vtmpBitmap.TransparentColor:=clBlue;
    vtmpBitmap.Width:=FDLen;
    vtmpBitmap.Height:=FDLen;
    vtmpBitmap.Canvas.Brush.Style:=TFPBrushStyle.bsSolid;
    //vtmpBitmap.Canvas.Brush.Color:=cBackColor;
    //vtmpBitmap.Canvas.FillRect(0,0,FDLen,FDLen);
    //vtmpBitmap.Canvas.Pen.Style:=TFPPenStyle.psSolid;
    //vtmpBitmap.Canvas.Pen.Color:=aCs;
    //vtmpBitmap.Canvas.Ellipse(0,0,FDLen-1,FDLen-1);
    }
    for xt := 0 to Self.Width - 1 do
    begin
      for yt := 0 to (Self.Height - 1) div 2 do
      begin
        aSwapC := Self.Canvas.Pixels[xt, Self.Height - 1 - yt];
        Self.Canvas.Pixels[xt, Self.Height - 1 - yt] := Self.Canvas.Pixels[xt, yt];
        Self.Canvas.Pixels[xt, yt]:=aSwapC;
      end;
      //若有中点，则不交换
    end;
    for yt := 0 to (Self.Height - 1) do
    begin
      for xt := 0 to (Self.Width - 1) div 2 do
      begin
      aSwapC := Self.Canvas.Pixels[(Self.Width - 1)-xt, yt];
      Self.Canvas.Pixels[(Self.Width - 1)-xt, yt] := Self.Canvas.Pixels[xt, yt];
      Self.Canvas.Pixels[xt, yt]:=aSwapC;
      end;
    end;
  end;
  //Self.Picture.Bitmap.TransparentMode := tmFixed;
  //Self.Picture.Bitmap.TransparentColor := Self.Canvas.Pixels[1, 1];
  //Self.Transparent := True;

end;

end.

